package utils

import (
	"errors"
	"mime/multipart"
	"reflect"
	"strconv"
)

func ConvertTo(kind reflect.Type, source interface{}) (interface{}, error) {
	b := &base{source: source}
	switch kind.Kind() {
	case reflect.String:
		b.ConvertToString()
	case reflect.Int:
		b.ConvertToInt()
	case reflect.Int8:
		b.ConvertToInt8()
	case reflect.Int16:
		b.ConvertToInt16()
	case reflect.Int32:
		b.ConvertToInt32()
	case reflect.Int64:
		b.ConvertToInt64()
	case reflect.Float32:
		b.ConvertToFloat32()
	case reflect.Float64:
		b.ConvertToFloat64()
	case reflect.Bool:
		b.ConvertToBool()
	case reflect.Ptr:
		b.ConvertToPtr(kind)
	default:
		return b.dest, errors.New("convert error")
	}
	return b.dest, nil
}

type Convert interface {
	ConvertToString()
	ConvertToInt()
	ConvertToInt8()
	ConvertToInt16()
	ConvertToInt32()
	ConvertToInt64()
	ConvertToFloat32()
	ConvertToFloat64()
	ConvertToBool()
	ConvertToPtr()
}

type base struct {
	source interface{}
	dest   interface{}
}

func (b *base) ConvertToString() {
	if data, ok := b.source.(string); ok {
		b.dest = data
	}
}

func (b *base) ConvertToInt() {
	if data, ok := b.source.(int); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseInt(str, 10, 64)
		if nil == err {
			b.dest = int(result)
		}
	}
}

func (b *base) ConvertToInt8() {
	if data, ok := b.source.(int8); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseInt(str, 10, 64)
		if nil == err {
			b.dest = int8(result)
		}
	}
}

func (b *base) ConvertToInt16() {
	if data, ok := b.source.(int16); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseInt(str, 10, 64)
		if nil == err {
			b.dest = int16(result)
		}
	}
}

func (b *base) ConvertToInt32() {
	if data, ok := b.source.(int32); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseInt(str, 10, 64)
		if nil == err {
			b.dest = int32(result)
		}
	}
}

func (b *base) ConvertToInt64() {
	if data, ok := b.source.(int64); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseInt(str, 10, 64)
		if nil == err {
			b.dest = result
		}
	}
}

func (b *base) ConvertToFloat32() {
	if data, ok := b.source.(float32); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseFloat(str, 64)
		if nil == err {
			b.dest = float32(result)
		}
	}
}

func (b *base) ConvertToFloat64() {
	if data, ok := b.source.(float64); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseFloat(str, 64)
		if nil == err {
			b.dest = result
		}
	}
}

func (b *base) ConvertToBool() {
	if data, ok := b.source.(bool); ok {
		b.dest = data
	} else {
		str := b.source.(string)
		result, err := strconv.ParseBool(str)
		if nil == err {
			b.dest = result
		}
	}
}

func (b *base) ConvertToPtr(kind reflect.Type) {
	if kind.String() == "*multipart.FileHeader" {
		if data, ok := b.source.(*multipart.FileHeader); ok {
			b.dest = data
		}
	}
}
